﻿using System;
using System.Net;

using System.Collections.Generic;
using caedisi.Web.DataModel;
using System.ComponentModel;
using caedisi.Common;
using System.Linq;
using System.Collections.ObjectModel;
using caedisi.Helpers;
using System.Windows;

namespace caedisi.Models
{
    /// <summary>
    /// The simulation class which is responsible to store the simulation properties and the algorihtm to process the execution
    /// </summary>
    public class Simulation : INotifyPropertyChanged
    {

        short[] tabX = new short[30];
        short[] tabY = new short[30];
        //int ind = 0;
        int subdivision = 0;
        int indicator;
        List<CellularAutomata> listOfCa = new List<CellularAutomata>();
        /// <summary>
        /// Gets the cellular automata.
        /// </summary>
        public CellularAutomata CellularAutomata
        {
            get;
            private set;
        }

        private int _CurrentStep;
        /// <summary>
        /// Gets or sets the current step.
        /// </summary>
        /// <value>
        /// The current step.
        /// </value>
        public int CurrentStep
        {
            get
            {
                return _CurrentStep;
            }
            set
            {
                if (_CurrentStep != value)
                {
                    int oldCurrentStep = _CurrentStep;
                    _CurrentStep = value;
                    this.RaisePropertyChanged("CurrentStep");
                    OnCurrentStepChanged(oldCurrentStep, value);

                }
            }
        }

        private int _SimulationEndConditionCellStateTypeId = (int)EnumCellStateType.Decontaminated;
        /// <summary>
        /// Gets or sets the simulation end condition cell state type id.
        /// </summary>
        /// <value>
        /// The simulation end condition cell state type id.
        /// </value>
        public int SimulationEndConditionCellStateTypeId
        {
            get
            {
                return _SimulationEndConditionCellStateTypeId;
            }
            set
            {
                if (_SimulationEndConditionCellStateTypeId != value)
                {
                    _SimulationEndConditionCellStateTypeId = value;
                    this.RaisePropertyChanged("SimulationEndConditionCellStateTypeId");
                    //OnCurrentStepChanged();
                }
            }
        }

        private EnumConditionEndOfSimulation _EnumConditionEndOfSimulation = EnumConditionEndOfSimulation.StateIsReached;
        /// <summary>
        /// Gets or sets the enum condition end of simulation.
        /// </summary>
        /// <value>
        /// The enum condition end of simulation.
        /// </value>
        public EnumConditionEndOfSimulation EnumConditionEndOfSimulation
        {
            get
            {
                return _EnumConditionEndOfSimulation;
            }
            set
            {
                if (_EnumConditionEndOfSimulation != value)
                {
                    _EnumConditionEndOfSimulation = value;
                    this.RaisePropertyChanged("EnumConditionEndOfSimulation");
                }
            }
        }

        private int _SimulationEndConditionNumberOfSteps = 10;
        /// <summary>
        /// Gets or sets the simulation end condition number of steps.
        /// </summary>
        /// <value>
        /// The simulation end condition number of steps.
        /// </value>
        public int SimulationEndConditionNumberOfSteps
        {
            get
            {
                return _SimulationEndConditionNumberOfSteps;
            }
            set
            {
                if (_SimulationEndConditionNumberOfSteps != value)
                {
                    _SimulationEndConditionNumberOfSteps = value;
                    this.RaisePropertyChanged("SimulationEndConditionNumberOfSteps");
                }
            }
        }


        private int _SimulationPlayModeTransitionTimeDelay = 1;
        /// <summary>
        /// Gets or sets the simulation play mode transition time delay.
        /// </summary>
        /// <value>
        /// The simulation play mode transition time delay.
        /// </value>
        public int SimulationPlayModeTransitionTimeDelay
        {
            get
            {
                return _SimulationPlayModeTransitionTimeDelay;
            }
            set
            {
                if (_SimulationPlayModeTransitionTimeDelay != value)
                {
                    _SimulationPlayModeTransitionTimeDelay = value;
                    this.RaisePropertyChanged("SimulationPlayModeTransitionTimeDelay");
                }
            }
        }

        private int _OutOfBoundCellStateTypeId = (int)EnumCellStateType.Decontaminated;
        /// <summary>
        /// Gets or sets the _ out of bound cell state type id. This is a state that the cell will see when they will request
        /// a neighbour that falls outside the cellular automata
        /// </summary>
        /// <value>
        /// The _ out of bound cell state type id.
        /// </value>
        public int OutOfBoundCellStateTypeId
        {
            get
            {
                return _OutOfBoundCellStateTypeId;
            }
            set
            {
                if (_OutOfBoundCellStateTypeId != value)
                {
                    _OutOfBoundCellStateTypeId = value;
                    this.RaisePropertyChanged("OutOfBoundCellStateTypeId");
                }
            }
        }

        /// <summary>
        /// Gets the system state dictionary. Contains a collection of all the state of each cellular automata cell during the entire process.
        /// The data structure of the SystemStateDictionary
        ///  - the key is a pair of of cell id and time 
        ///  - the value is an object SimulationStepItem that stores the cell state at each step time t
        /// </summary>
        public Dictionary<Tuple<Guid, int>, SimulationIterationItem> SystemStateDictionary { get; private set; }

        /// <summary>
        /// Initializes a new instance of the <see cref="Simulation"/> class.
        /// </summary>
        private Simulation()
        {
            SystemStateDictionary = new Dictionary<Tuple<Guid, int>, SimulationIterationItem>();
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="Simulation"/> class.
        /// </summary>
        /// <param name="cellularAutomata">The cellular automata.</param>
        public Simulation(CellularAutomata cellularAutomata)
            : this()
        {
            this.CellularAutomata = cellularAutomata;
            this.CurrentStep = 0;
            this.SystemStateDictionary.Clear();

            ExecutionStatus = EnumSimulationExecutionStatus.Pause;
            //setting the association
            cellularAutomata.CurrentSimulation = this;
        }



        /// <summary>
        /// Initializes a new instance of the <see cref="Simulation"/> class.
        /// </summary>
        /// <param name="cellularAutomata">The cellular automata.</param>
        public Simulation(CellularAutomata cellularAutomata, short[] tabX, short[] tabY, int subdivision, List<CellularAutomata> listOfCa, int ind)
            : this()
        {
            this.CellularAutomata = cellularAutomata;
            this.CurrentStep = 0;
            this.SystemStateDictionary.Clear();

            ExecutionStatus = EnumSimulationExecutionStatus.Pause;
            //setting the association
            cellularAutomata.CurrentSimulation = this;

            this.tabX = tabX;
            this.tabY = tabY;
            this.subdivision = subdivision;
            this.indicator = ind;
            foreach (CellularAutomata ca in listOfCa)
            {
                this.listOfCa.Add(ca);
            }
        }


        /// <summary>
        /// Called when [current step changed].
        /// </summary>
        /// <param name="previousStep">The previous step.</param>
        /// <param name="newStep">The new step.</param>
        private void OnCurrentStepChanged(int previousStep, int newStep)
        {
            if (previousStep < newStep)  //e.g from 0->1, 1->10 etc
            {
                //at the initial state, we need to save the system state dictionary.
                if (previousStep == 0 && newStep == 1)
                {
                    foreach (Cell cell in this.CellularAutomata.Cells)
                    {
                        int? immunityValue = (cell.CellStateTypeId == ((int)EnumCellStateType.Decontaminated)) ? 0 : (int?)null;
                        SimulationIterationItem iterationItem = GetSimulationIterationItem(cell.CellId, 0, true);
                        iterationItem.CellStateTypeId = cell.CellStateTypeId;
                        iterationItem.ImmunityTimerValue = immunityValue;
                        Tuple<Guid, int> newIterationItemKey = new Tuple<Guid, int>(cell.CellId, 0);
                        this.SystemStateDictionary[newIterationItemKey] = iterationItem;

                    }
                }

                if (subdivision == 0)
                    //we process the new states of all cells of the cellular automata
                    ProcessTransitionRulesAlgorithm(this.CellularAutomata, newStep);
                else
                    ProcessSubdivisionTransitionRulesAlgorithm(this.CellularAutomata, newStep);

            }

            RefreshCellularAutomataCells(newStep);
        }


        /// <summary>
        /// Processes the transition rules algorithm. The goal is to produce new state for each cell of the cellular automata 
        /// based on which transition rules is eligible applied to that cell. The data structure that holds the state for each
        /// step is the SystemStateDictionary.       
        /// </summary>
        /// <param name="cellularAutomata">The cellular automata.</param>
        /// <param name="newStep">The new step.</param>
        private void ProcessTransitionRulesAlgorithm(Web.DataModel.CellularAutomata cellularAutomata, int newStep)
        {
            int numberOfRows = cellularAutomata.Height;
            int numberOfColumns = cellularAutomata.Width;

            for (int i = 0; i < numberOfRows; i++)
            {
                for (int j = 0; j < numberOfColumns; j++)
                {
                    int k = 0;  // only 2D for now
                    Cell myCell = cellularAutomata.CellularAutomataAsArray[i, j, k];
                    SimulationIterationItem previousIterationItem = GetSimulationIterationItem(myCell.CellId, newStep - 1, false);
                    SimulationIterationItem newIterationItem = GetSimulationIterationItem(myCell.CellId, newStep, true);
                    newIterationItem.Reset();

                    //grab which rules applies to myCell
                    foreach (TransitionRule rule in cellularAutomata.TransitionRules)
                    {
                        bool doesCellCurrentStateSatisfyRule =
                            DoesCellConfigurationSatisfyTransitionRule(myCell, rule, cellularAutomata);
                        if (doesCellCurrentStateSatisfyRule)
                            newIterationItem.TransitionRulesCause.Add(rule);
                    }

                    //by default, the result state is the old value
                    int resultCellStateTypeId = myCell.CellStateTypeId;
                    if (newIterationItem.TransitionRulesCause.Count > 0)
                    {
                        if (newIterationItem.IsDeterministic)
                        {
                            int tentativeResultCellStateTypeId =
                                newIterationItem.TransitionRulesCause.First().ResultCellStateTypeId;
                            if (tentativeResultCellStateTypeId == ((int)EnumCellStateType.Decontaminated))
                            {
                                resultCellStateTypeId = ((int)EnumCellStateType.Decontaminated);
                                //each time the cell gets decontaminated (i.e the virus has been cleant), 
                                //the immunity timer is reset
                                newIterationItem.ImmunityTimerValue = cellularAutomata.ImmunityTime;
                            }
                            else if (tentativeResultCellStateTypeId == ((int)EnumCellStateType.Contaminated))
                            {
                                //it will goes to contaminated if the cell is no more immune
                                if (previousIterationItem == null || previousIterationItem.ImmunityTimerValue == 0)
                                {
                                    resultCellStateTypeId = ((int)EnumCellStateType.Contaminated);
                                }
                                else
                                    resultCellStateTypeId = myCell.CellStateTypeId;

                                //decrease the timer
                                newIterationItem.ImmunityTimerValue =
                                    (previousIterationItem.ImmunityTimerValue > 0 ?
                                    previousIterationItem.ImmunityTimerValue - 1 : 0);
                            }
                            else
                                resultCellStateTypeId = tentativeResultCellStateTypeId;
                        }
                        else
                        {   // Undeterministic (We found multiple transition rules that can be applied to the 
                            // cells but their result state are different) The Code decision is to keep the previous
                            // transition result but we flag that the cell has an issue                         
                            resultCellStateTypeId = myCell.CellStateTypeId;
                            //even for underterministic case, we still decrease the immunity timer when the previous 
                            //state has a timer value set
                            if (previousIterationItem.CellStateTypeId == ((int)EnumCellStateType.Decontaminated))
                                newIterationItem.ImmunityTimerValue =
                                    (previousIterationItem.ImmunityTimerValue > 0 ?
                                    previousIterationItem.ImmunityTimerValue - 1 : 0);
                        }
                    }
                    else
                    {
                        if (resultCellStateTypeId == ((int)EnumCellStateType.Decontaminated))
                        {
                            newIterationItem.ImmunityTimerValue =
                                (previousIterationItem.ImmunityTimerValue > 0 ?
                                previousIterationItem.ImmunityTimerValue - 1 : 0);
                        }
                    }
                    //setting the final result state
                    newIterationItem.CellStateTypeId = resultCellStateTypeId;

                    Tuple<Guid, int> newIterationItemKey = new Tuple<Guid, int>(myCell.CellId, newStep);
                    this.SystemStateDictionary[newIterationItemKey] = newIterationItem;
                }
            }
        }


        //********************************************


        /// <summary>
        /// Processes the transition rules algorithm. The goal is to produce new state for each cell of the cellular automata 
        /// based on which transition rules is eligible applied to that cell. The data structure that holds the state for each
        /// step is the SystemStateDictionary.       
        /// </summary>
        /// <param name="cellularAutomata">The cellular automata.</param>
        /// <param name="newStep">The new step.</param>
        private void ProcessSubdivisionTransitionRulesAlgorithm(Web.DataModel.CellularAutomata cellularAutomata, int newStep)
        {
            //int numberOfRows = cellularAutomata.Height;
            //int numberOfColumns = cellularAutomata.Width;
            int indexCA = 0;
            //MessageBox.Show(listOfCa.Count.ToString());
            //MessageBox.Show(listOfCa[0].ToString());
            //MessageBox.Show(listOfCa[1].ToString());
            int index = 0;
            while (tabX[index] != -1)
            {
                //MessageBox.Show(tabX[index].ToString());
                for (int i = tabX[index]; i <= tabX[index + 1]; i++)
                {
                    for (int j = tabY[index]; j <= tabY[index + 1]; j++)
                    {
                        int k = 0;  // only 2D for now
                        Cell myCell = cellularAutomata.CellularAutomataAsArray[i, j, k];
                        SimulationIterationItem previousIterationItem = GetSimulationIterationItem(myCell.CellId, newStep - 1, false);
                        SimulationIterationItem newIterationItem = GetSimulationIterationItem(myCell.CellId, newStep, true);
                        newIterationItem.Reset();

                        //grab which rules applies to myCell
                        foreach (TransitionRule rule in listOfCa[indexCA].TransitionRules)
                        {

                            bool doesCellCurrentStateSatisfyRule =
                                DoesCellConfigurationSatisfyTransitionRule(myCell, rule, cellularAutomata);
                            if (doesCellCurrentStateSatisfyRule)
                                newIterationItem.TransitionRulesCause.Add(rule);
                        }

                        //by default, the result state is the old value
                        int resultCellStateTypeId = myCell.CellStateTypeId;
                        if (newIterationItem.TransitionRulesCause.Count > 0)
                        {
                            if (newIterationItem.IsDeterministic)
                            {
                                int tentativeResultCellStateTypeId =
                                    newIterationItem.TransitionRulesCause.First().ResultCellStateTypeId;
                                if (tentativeResultCellStateTypeId == ((int)EnumCellStateType.Decontaminated))
                                {
                                    resultCellStateTypeId = ((int)EnumCellStateType.Decontaminated);
                                    //each time the cell gets decontaminated (i.e the virus has been cleant), 
                                    //the immunity timer is reset
                                    newIterationItem.ImmunityTimerValue = cellularAutomata.ImmunityTime;
                                }
                                else if (tentativeResultCellStateTypeId == ((int)EnumCellStateType.Contaminated))
                                {
                                    //it will goes to contaminated if the cell is no more immune
                                    if (previousIterationItem == null || previousIterationItem.ImmunityTimerValue == 0)
                                    {
                                        resultCellStateTypeId = ((int)EnumCellStateType.Contaminated);
                                    }
                                    else
                                        resultCellStateTypeId = myCell.CellStateTypeId;

                                    //decrease the timer
                                    newIterationItem.ImmunityTimerValue =
                                        (previousIterationItem.ImmunityTimerValue > 0 ?
                                        previousIterationItem.ImmunityTimerValue - 1 : 0);
                                }
                                else
                                    resultCellStateTypeId = tentativeResultCellStateTypeId;
                            }
                            else
                            {   // Undeterministic (We found multiple transition rules that can be applied to the 
                                // cells but their result state are different) The Code decision is to keep the previous
                                // transition result but we flag that the cell has an issue                         
                                resultCellStateTypeId = myCell.CellStateTypeId;
                                //even for underterministic case, we still decrease the immunity timer when the previous 
                                //state has a timer value set
                                if (previousIterationItem.CellStateTypeId == ((int)EnumCellStateType.Decontaminated))
                                    newIterationItem.ImmunityTimerValue =
                                        (previousIterationItem.ImmunityTimerValue > 0 ?
                                        previousIterationItem.ImmunityTimerValue - 1 : 0);
                            }
                        }
                        else
                        {
                            if (resultCellStateTypeId == ((int)EnumCellStateType.Decontaminated))
                            {
                                newIterationItem.ImmunityTimerValue =
                                    (previousIterationItem.ImmunityTimerValue > 0 ?
                                    previousIterationItem.ImmunityTimerValue - 1 : 0);
                            }
                        }
                        //setting the final result state
                        newIterationItem.CellStateTypeId = resultCellStateTypeId;

                        Tuple<Guid, int> newIterationItemKey = new Tuple<Guid, int>(myCell.CellId, newStep);
                        this.SystemStateDictionary[newIterationItemKey] = newIterationItem;

                    }
                }
                //ind = index;
                index += 2;
                indexCA++;


                //********************



                //for (int i = 4; i < numberOfRows; i++)
                //{
                //    for (int j = 0; j < numberOfColumns; j++)
                //    {
                //        int k = 0;  // only 2D for now
                //        Cell myCell = cellularAutomata.CellularAutomataAsArray[i, j, k];
                //        SimulationIterationItem previousIterationItem = GetSimulationIterationItem(myCell.CellId, newStep - 1, false);
                //        SimulationIterationItem newIterationItem = GetSimulationIterationItem(myCell.CellId, newStep, true);
                //        newIterationItem.Reset();

                //        //grab which rules applies to myCell
                //        foreach (TransitionRule rule in cellularAutomata.TransitionRules)
                //        {
                //            bool doesCellCurrentStateSatisfyRule =
                //                DoesCellConfigurationSatisfyTransitionRule(myCell, rule, cellularAutomata);
                //            if (doesCellCurrentStateSatisfyRule)
                //                newIterationItem.TransitionRulesCause.Add(rule);
                //        }

                //        //by default, the result state is the old value
                //        int resultCellStateTypeId = myCell.CellStateTypeId;
                //        if (newIterationItem.TransitionRulesCause.Count > 0)
                //        {
                //            if (newIterationItem.IsDeterministic)
                //            {
                //                int tentativeResultCellStateTypeId =
                //                    newIterationItem.TransitionRulesCause.First().ResultCellStateTypeId;
                //                if (tentativeResultCellStateTypeId == ((int)EnumCellStateType.Decontaminated))
                //                {
                //                    resultCellStateTypeId = ((int)EnumCellStateType.Decontaminated);
                //                    //each time the cell gets decontaminated (i.e the virus has been cleant), 
                //                    //the immunity timer is reset
                //                    newIterationItem.ImmunityTimerValue = cellularAutomata.ImmunityTime;
                //                }
                //                else if (tentativeResultCellStateTypeId == ((int)EnumCellStateType.Contaminated))
                //                {
                //                    //it will goes to contaminated if the cell is no more immune
                //                    if (previousIterationItem == null || previousIterationItem.ImmunityTimerValue == 0)
                //                    {
                //                        resultCellStateTypeId = ((int)EnumCellStateType.Contaminated);
                //                    }
                //                    else
                //                        resultCellStateTypeId = myCell.CellStateTypeId;

                //                    //decrease the timer
                //                    newIterationItem.ImmunityTimerValue =
                //                        (previousIterationItem.ImmunityTimerValue > 0 ?
                //                        previousIterationItem.ImmunityTimerValue - 1 : 0);
                //                }
                //                else
                //                    resultCellStateTypeId = tentativeResultCellStateTypeId;
                //            }
                //            else
                //            {   // Undeterministic (We found multiple transition rules that can be applied to the 
                //                // cells but their result state are different) The Code decision is to keep the previous
                //                // transition result but we flag that the cell has an issue                         
                //                resultCellStateTypeId = myCell.CellStateTypeId;
                //                //even for underterministic case, we still decrease the immunity timer when the previous 
                //                //state has a timer value set
                //                if (previousIterationItem.CellStateTypeId == ((int)EnumCellStateType.Decontaminated))
                //                    newIterationItem.ImmunityTimerValue =
                //                        (previousIterationItem.ImmunityTimerValue > 0 ?
                //                        previousIterationItem.ImmunityTimerValue - 1 : 0);
                //            }
                //        }
                //        else
                //        {
                //            if (resultCellStateTypeId == ((int)EnumCellStateType.Decontaminated))
                //            {
                //                newIterationItem.ImmunityTimerValue =
                //                    (previousIterationItem.ImmunityTimerValue > 0 ?
                //                    previousIterationItem.ImmunityTimerValue - 1 : 0);
                //            }
                //        }
                //        //setting the final result state
                //        newIterationItem.CellStateTypeId = resultCellStateTypeId;

                //        Tuple<Guid, int> newIterationItemKey = new Tuple<Guid, int>(myCell.CellId, newStep);
                //        this.SystemStateDictionary[newIterationItemKey] = newIterationItem;
                //    }
                //}


                //********************
            }



        }

        /// <summary>
        /// Gets the simulation iteration item.
        /// </summary>
        /// <param name="cellId">The cell id.</param>
        /// <param name="step">The step.</param>
        /// <param name="createIfNull">if set to <c>true</c> [create if null].</param>
        /// <returns></returns>
        public SimulationIterationItem GetSimulationIterationItem(Guid cellId, int step, bool createIfNull)
        {
            Tuple<Guid, int> existingTupleKey = this.SystemStateDictionary.Keys.Where(tuple => tuple.Item1.CompareTo(cellId) == 0 && tuple.Item2 == step).SingleOrDefault();

            if (existingTupleKey == null)
            {
                if (createIfNull)
                    return new SimulationIterationItem(cellId, step);
                else
                    return null;
            }
            else
            {
                return this.SystemStateDictionary[existingTupleKey];
            }
        }



        /// <summary>
        /// Doeses the cell configuration satisfy transition rule.
        /// </summary>
        /// <param name="myCell">My cell.</param>
        /// <param name="rule">The rule.</param>
        /// <param name="cellularAutomata">The cellular automata.</param>
        /// <returns></returns>
        private bool DoesCellConfigurationSatisfyTransitionRule(Cell myCell, TransitionRule rule, CellularAutomata cellularAutomata)
        {
            if (myCell.CellStateTypeId != rule.CurrentCellStateTypeId)
                return false;

            // we now validate that the neighbourhood of myCell respect the neighbourhood defined in the transition rule.
            // the algorithm proceed by elimination
            int numberOfRows = cellularAutomata.Height;
            int numberOfColumns = cellularAutomata.Width;

            foreach (NeighbourhoodStateConfiguration ruleStateConfiguration in rule.NeighbourhoodStateConfigurations)
            {
                if (((EnumCellStateType)ruleStateConfiguration.CellStateTypeId) != EnumCellStateType.Generic)
                {
                    //int xIndexNeighbour = myCell.x + ruleStateConfiguration.x_offset;
                    //int yIndexNeighbour = myCell.y + ruleStateConfiguration.y_offset;
                    //int zIndexNeighbour = myCell.z + ruleStateConfiguration.z_offset;

                    ////find the cell pointed by these coordinates. TODO make it complete
                    //int neighbourCellStateTypeId;

                    //bool doesXIndexExist = cellularAutomata.CircularVertical   || (xIndexNeighbour>=0 && xIndexNeighbour<numberOfRows);
                    //bool doesYIndexExist = cellularAutomata.CircularHorizontal || (yIndexNeighbour>=0 && yIndexNeighbour<numberOfColumns);
                    //bool doesZIndexExist = true;

                    //if (doesXIndexExist && doesYIndexExist && doesZIndexExist)
                    //{
                    //    neighbourCellStateTypeId = cellularAutomata.CellularAutomataAsArray[
                    //        EntityHelper.MathMod(xIndexNeighbour,numberOfRows) , 
                    //        EntityHelper.MathMod(yIndexNeighbour, numberOfColumns),
                    //        zIndexNeighbour].CellStateTypeId;
                    //}
                    //else
                    //{
                    //    neighbourCellStateTypeId = this.OutOfBoundCellStateTypeId;
                    //}

                    int neighbourCellStateTypeId = EntityHelper.GetNeighbourCellStateTypeId(myCell,
                        cellularAutomata.CellularAutomataAsArray,
                        ruleStateConfiguration,
                        cellularAutomata.CircularVertical,
                        cellularAutomata.CircularHorizontal,
                        this.OutOfBoundCellStateTypeId);

                    if (ruleStateConfiguration.CellStateTypeId != neighbourCellStateTypeId)
                        return false;
                }
            }

            //we found nothing that contradicts the state so it is eligible
            return true;
        }


        /// <summary>
        /// Refreshes the cellular automata cells.
        /// </summary>
        /// <param name="step">The step.</param>
        private void RefreshCellularAutomataCells(int step)
        {
            //IEnumerable<KeyValuePair<Tuple<Guid,int>, SimulationIterationItem >> filteredDictionary = this.SystemStateDictionary.Where(KeyValuePair => KeyValuePair.Key.Item2==step);

            foreach (Cell cell in this.CellularAutomata.Cells)
            {
                Tuple<Guid, int> key = null;
                try
                {
                    key = this.SystemStateDictionary.Keys.First(tuple => tuple.Item1.CompareTo(cell.CellId) == 0 && tuple.Item2 == step);
                }
                catch
                {
                    ;
                }

                if (key != null)
                    cell.SimulationIterationItem = this.SystemStateDictionary[key];
            }

            this.RaisePropertyChanged("CurrentQuantityDecontaminatingCells");
            this.RaisePropertyChanged("CurrentQuantityDecontaminatedCells");
            this.RaisePropertyChanged("CurrentQuantityContaminatedCells");

            this.RaisePropertyChanged("CurrentQuantityDecontaminatingCellsPercentage");
            this.RaisePropertyChanged("CurrentQuantityDecontaminatedCellsPercentage");
            this.RaisePropertyChanged("CurrentQuantityContaminatedCellsPercentage");

            this.RaisePropertyChanged("CurrentQuantityDecontaminatingCellsZoom");
            this.RaisePropertyChanged("CurrentQuantityDecontaminatedCellsZoom");
            this.RaisePropertyChanged("CurrentQuantityContaminatedCellsZoom");
        }

        #region INotifyPropertyChanged

        public event PropertyChangedEventHandler PropertyChanged;
        /// <summary>
        /// Raises the property changed.
        /// </summary>
        /// <param name="propertyName">Name of the property.</param>
        protected virtual void RaisePropertyChanged(string propertyName)
        {
            PropertyChangedEventHandler handler = this.PropertyChanged;
            if (handler != null)
            {
                handler(this, new PropertyChangedEventArgs(propertyName));
            }
        }

        #endregion


        private bool _CanPlay;
        public bool CanPlay
        {
            get
            {
                return _CanPlay;
            }
            set
            {
                if (_CanPlay != value)
                {
                    _CanPlay = value;
                    this.RaisePropertyChanged("CanPlay");
                }
            }
        }

        private bool _CanPlayNext;
        public bool CanPlayNext
        {
            get
            {
                return _CanPlayNext;
            }
            set
            {
                if (_CanPlayNext != value)
                {
                    _CanPlayNext = value;
                    this.RaisePropertyChanged("CanPlayNext");
                }
            }
        }


        private bool _CanPlayPrevious;
        public bool CanPlayPrevious
        {
            get
            {
                return _CanPlayPrevious;
            }
            set
            {
                if (_CanPlayPrevious != value)
                {
                    _CanPlayPrevious = value;
                    this.RaisePropertyChanged("CanPlayPrevious");
                }
            }
        }

        private bool _CanPlayFirst;
        public bool CanPlayFirst
        {
            get
            {
                return _CanPlayFirst;
            }
            set
            {
                if (_CanPlayFirst != value)
                {
                    _CanPlayFirst = value;
                    this.RaisePropertyChanged("CanPlayFirst");
                }
            }
        }

        private bool _CanPlayLast;
        public bool CanPlayLast
        {
            get
            {
                return _CanPlayLast;
            }
            set
            {
                if (_CanPlayLast != value)
                {
                    _CanPlayLast = value;
                    this.RaisePropertyChanged("CanPlayLast");
                }
            }
        }

        private bool _CanPause;
        public bool CanPause
        {
            get
            {
                return _CanPause;
            }
            set
            {
                if (_CanPause != value)
                {
                    _CanPause = value;
                    this.RaisePropertyChanged("CanPause");
                }
            }
        }

        public EnumSimulationExecutionStatus ExecutionStatus { get; set; }

        public int CurrentQuantityDecontaminatingCells
        {
            get
            {
                return EntityHelper.GetCardinalitySpecificState(this, this.CurrentStep, EnumCellStateType.Decontaminating);
            }
        }

        public double CurrentQuantityDecontaminatingCellsPercentage
        {
            get
            {
                return EntityHelper.GetCardinalitySpecificStatePercentage(this, this.CurrentStep, EnumCellStateType.Decontaminating, this.CellularAutomata.Width * this.CellularAutomata.Height);
            }
        }

        /// <summary>
        /// CurrentQuantityDecontaminatingCells with zoom
        /// </summary>
        public double CurrentQuantityDecontaminatingCellsZoom
        {
            get
            {
                return EntityHelper.GetCardinalitySpecificStateZoom(this, this.CurrentStep, EnumCellStateType.Decontaminating, this.CellularAutomata.Width * this.CellularAutomata.Height);
            }
        }

        public int CurrentQuantityDecontaminatedCells
        {
            get
            {
                return EntityHelper.GetCardinalitySpecificState(this, this.CurrentStep, EnumCellStateType.Decontaminated);
            }
        }

        public double CurrentQuantityDecontaminatedCellsPercentage
        {
            get
            {
                return EntityHelper.GetCardinalitySpecificStatePercentage(this, this.CurrentStep, EnumCellStateType.Decontaminated, this.CellularAutomata.Width * this.CellularAutomata.Height);
            }
        }

        /// <summary>
        /// CurrentQuantityDecontaminatedCells with zoom
        /// </summary>
        public double CurrentQuantityDecontaminatedCellsZoom
        {
            get
            {
                return EntityHelper.GetCardinalitySpecificStateZoom(this, this.CurrentStep, EnumCellStateType.Decontaminated, this.CellularAutomata.Width * this.CellularAutomata.Height);
            }
        }

        public int CurrentQuantityContaminatedCells
        {
            get
            {
                return EntityHelper.GetCardinalitySpecificState(this, this.CurrentStep, EnumCellStateType.Contaminated);
            }
        }

        public double CurrentQuantityContaminatedCellsPercentage
        {
            get
            {
                return EntityHelper.GetCardinalitySpecificStatePercentage(this, this.CurrentStep, EnumCellStateType.Contaminated, this.CellularAutomata.Width * this.CellularAutomata.Height);
            }
        }

        /// <summary>
        /// CurrentQuantityContaminatedCells with zoom
        /// </summary>
        public double CurrentQuantityContaminatedCellsZoom
        {
            get
            {
                return EntityHelper.GetCardinalitySpecificStateZoom(this, this.CurrentStep, EnumCellStateType.Contaminated, this.CellularAutomata.Width * this.CellularAutomata.Height);
            }
        }

        public double TotalQuantityDecontaminatingCells
        {
            get
            {
                return EntityHelper.GetCardinalitySpecificState(this, this.CurrentStep, EnumCellStateType.Decontaminating);
            }
        }

        public int TotalQuantityCells
        {
            get
            {
                if (this.CellularAutomata == null)
                    return 0;

                return this.CellularAutomata.Width * this.CellularAutomata.Height;
            }
        }

    }
}
